Crate stateroom

source ·
Expand description

Stateroom is a minimalist framework for developing stateful WebSocket applications.

Stateroom apps implement the SimpleStateroomService trait, which provides a way for the app to hook into events when clients connect, disconnect, and send messages. Additionally, Stateroom provides a simple mechanism for invoking events in the future with a timer.

A simple chat server looks like this:

use stateroom::*;
use std::collections::HashMap;

#[derive(Default)]
struct ChatServer {
    /// The server's only state is a mapping of client ID to username.
    client_to_nickname: HashMap<ClientId, String>,
}

impl SimpleStateroomService for ChatServer {
    fn new(room_id: &str, _: &impl StateroomContext) -> Self {
        Default::default()
    }

    /// This is called when a user connects.
    fn connect(&mut self, client: ClientId, ctx: &impl StateroomContext) {
        let username = format!("client{}", u32::from(client));

        // Send a welcome message.
        ctx.send_message(client,
            &format!("Welcome to the chat! Your name is {}. \
                     Send /nick <username> to change it.",
                     &username));

        // Alert all other connected users to the new user.
        ctx.send_message(MessageRecipient::Broadcast,
            &format!("{} has joined the chat", &username));
    }

    /// This is called when a user disconnects.
    fn disconnect(&mut self, client: ClientId, ctx: &impl StateroomContext) {
        let username = self.client_to_nickname.remove(&client).unwrap();

        // Alert all remaining users that a user has left.
        ctx.send_message(MessageRecipient::Broadcast,
           &format!("{} has left the chat", &username));
    }

    /// This is called when a user sends a message.
    fn message(&mut self, client: ClientId, message: &str, ctx: &impl StateroomContext) {
        if let Some(new_nick) = message.strip_prefix("/nick ") {
            // This message is a /nick command, so process accordingly.
            let old_nick = self.client_to_nickname.insert(client, new_nick.to_string()).unwrap();
            ctx.send_message(MessageRecipient::Broadcast,
               &format!("{} is now known as {}", old_nick, new_nick));
        } else {
            // Broadcast the message to all connected users, prefixed by the username.
            let username = self.client_to_nickname.get(&client).unwrap();
            ctx.send_message(MessageRecipient::Broadcast,
               &format!("{}: {}", username, message));
        }
    }
}

Structs

Enums

Traits